package cn.yanghan.service.impl;

import cn.yanghan.dto.SMSSendLogDto;
import cn.yanghan.dto.sendSmsCodeDto;
import cn.yanghan.service.IverifycodeService;
import cn.yanghan.utils.exception.Assert;
import cn.yanghan.utils.exception.BusinessException;
import cn.yanghan.utils.util.StrUtils;
import cn.yanghan.utils.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class verifycodeServiceImpl implements IverifycodeService {

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 图片验证码
     * 1.参数判断
     * 2.创建一个4位的随机字符串--图片验证码 xxoo
     * 3.把图片验证码存储到redis，使用前端传入的key
     * 4.把xxoo生成到一个图片上-使用工具
     * 5.把图片编程base64编码的字符串，并返回
     * @param key redis的key
     * @return
     */
    @Override
    public String creatImageCode(String key) {
             //* 1.参数判断
        Assert.assertNotEmpty(key,"参数错误");
        //* 2.创建一个4位的随机字符串--图片验证码 xxoo
        String code = StrUtils.getComplexRandomString(4);
        //* 3.把图片验证码存储到redis，使用前端传入的key
        redisTemplate.opsForValue().set(key,code,5, TimeUnit.MINUTES);
        try{
            //* 4.把xxoo生成到一个图片上-使用工具
            // * 5.把图片编程base64编码的字符串，并返回
            return VerifyCodeUtils.VerifyCode(135,35,code);
        }catch (IOException e){
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 发送短信验证码
     * 1.校验参数(参数：手机号，key，图片验证码)
     * 2.校验图片验证码必须正确，从redis里面查询，进行匹配
     * 3.尝试获取上一次发送记录
     *
     * 4.如果有：
     * 4.1.当前时间-上次发送时间必须大于60s
     * 4.2.小于60s，报错，提示发送过于频繁
     * 4.3.满足条件：使用上一次验证码
     * 5.如果没有：创建短信验证码
     * 6.短信验证码存储到redis，设置过期时间‘
     *      key与value分别是什么
     *      使用手机号作为： sms：phone  value：时间，验证码
     * 7.调用短信网关发送短信验证码
     * 8.数据库存储短信验证码发送记录
     *
     * @param dto 参数对象
     */
    @Override
    public void sendSmsCode(sendSmsCodeDto dto) {
         //* 1.校验参数(参数：手机号，key，图片验证码)
        String imageCode = dto.getImageCode();
        String imageCodeKey = dto.getImageCodeKey();
        String mobile = dto.getMobile();


        //* 2.校验图片验证码必须正确，从redis里面查询，进行匹配
        String CodeKeyInRedis = (String) redisTemplate.opsForValue().get(imageCodeKey);
        Assert.assertNotEmpty(CodeKeyInRedis,"图片验证码过期或者无效");
        if(!CodeKeyInRedis.equalsIgnoreCase(imageCode)){
            throw new BusinessException("图片验证码错误");
        }
        //* 3.尝试获取上一次发送记录
        //"sms:"+mobile
        String smsCodeKey ="sms:"+dto.getMobile() ;
        SMSSendLogDto DtolastSend = (SMSSendLogDto) redisTemplate.opsForValue().get(smsCodeKey);

        String smsCode = null;
        Date now = new Date();
        if(DtolastSend!=null){
            //* 4.如果有：
            //* 4.1.当前时间-上次发送时间必须大于60s
            if((now.getTime()-DtolastSend.getSendTime())/1000<1){
                //* 4.2.小于60s，报错，提示发送过于频繁
                throw new BusinessException("发送验证码过于频繁");
            }
            //* 4.3.满足条件：使用上一次验证码
            smsCode = DtolastSend.getCode();
        }else {
            //* 5.如果没有：创建短信验证码
            smsCode = StrUtils.getRandomString(4);
        }

        // * 6.短信验证码存储到redis，设置过期时间‘
        //*使用手机号作为： sms：phone  value：时间，验证码
        SMSSendLogDto smsSendLogDto = new SMSSendLogDto(smsCode, now.getTime());
        redisTemplate.opsForValue().set(smsCodeKey,smsSendLogDto,5,TimeUnit.MINUTES);
        //* 7.调用短信网关发送短信验证码
        log.info("发送短信验证码{}",smsCode);
        //* 8.数据库存储短信验证码发送记录
        log.info("保存数据到DB");
    }
}
